//
//  WNReadTools.swift
//  WalkNovel
//
//  Created by Kevin on 2023/7/20.
//

import UIKit

let READ_RECORD = "READ_RECORD"

/// 记录当前章节阅读到的坐标
var READ_RECORD_CURRENT_CHAPTER_LOCATION: Int = 0

let RECORD_RECT = CGRect(origin: .init(x: 0, y: StatusBarHeight), size: .init(width: ScreenW-24, height: ScreenH-StatusBarHeight-TabBarMargin-48))

var CACHES_PATH = (NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first ?? "")

/// 获得 CTFrame
func getFrameRef(_ attrString: NSAttributedString, _ rect: CGRect = RECORD_RECT) -> CTFrame {
    let framesetter = CTFramesetterCreateWithAttributedString(attrString)
    let path = CGPath(rect: rect, transform: nil)
    let frameRef = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, nil)
    return frameRef
}

/// 内容分页
func pageing(_ attrString: NSAttributedString) -> [ChapterPageModel] {
    var rangeArr = [NSRange]()
    let framesetter = CTFramesetterCreateWithAttributedString(attrString as CFAttributedString)
    let path = CGPath(rect: RECORD_RECT, transform: nil)
    var range = CFRangeMake(0, 0)
    var rangeOffset = 0
    repeat {
        let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(rangeOffset, 0), path, nil)
        range = CTFrameGetVisibleStringRange(frame)
        rangeArr.append(NSMakeRange(rangeOffset, range.length))
        rangeOffset += range.length
    }while (
        range.location + range.length < attrString.length
    )
    var pageModels: [ChapterPageModel] = []
    if !rangeArr.isEmpty {
        let count = rangeArr.count
        for i in 0..<count {
            let range = rangeArr[i]
            let pageModel = ChapterPageModel()
            let content = attrString.attributedSubstring(from: range)
            pageModel.range = range
            pageModel.content = content
            pageModel.page = NSNumber(value: i)
            pageModel.contentH = NSNumber(value: getAttrStringHeight(content, ScreenW-24))
            pageModels.append(pageModel)
        }
    }
    return pageModels
}
                                   
func getAttrStringHeight(_ attrString: NSAttributedString, _ maxW: CGFloat) -> CGFloat {
    var height: CGFloat = 0
    if attrString.length > 0 {
        // 注意设置的高度必须大于文本高度
        let maxH:CGFloat = 2000
        let framesetter = CTFramesetterCreateWithAttributedString(attrString)
        let drawingRect = CGRect(x: 0, y: 0, width: maxW, height: maxH)
        let path = CGPath(rect: drawingRect, transform: nil)
        let frameRef = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, nil)
        let lines = CTFrameGetLines(frameRef) as! [CTLine]
        var origins:[CGPoint] = Array(repeating: CGPoint.zero, count: lines.count)
        CTFrameGetLineOrigins(frameRef, CFRangeMake(0, 0), &origins)
        let lineY = origins.last!.y
        var lineAscent:CGFloat = 0
        var lineDescent:CGFloat = 0
        var lineLeading:CGFloat = 0
        CTLineGetTypographicBounds(lines.last!, &lineAscent, &lineDescent, &lineLeading)
        height = maxH - lineY + CGFloat(ceilf(Float(lineDescent)))
    }
    return height
}
                                           
class SNReadConfigure: NSObject {
    
    static let shared = SNReadConfigure()
    
    var lineSpacing: CGFloat {
        return wn_toCGFloat(getReadConfigItem("space"))
    }
    var paragraphSpacing: CGFloat {
        return 10
    }
    var textColor: UIColor {
        return isDark() ? .init(named: "gray_777777")! : .black
    }
    
    func font(_ isChapter: Bool = false) -> UIFont {
        let fontStr = wn_toString(getReadConfigItem("font"))
        var fontName = UIFont.ESFontName.regular
        if fontStr == "regular" {
            fontName = .regular
        }else if fontStr == "floane" {
            fontName = .floane
        }else if fontStr == "national" {
            fontName = .national
        }else if fontStr == "medium" {
            fontName = .medium
        }
        let fontSize = wn_toCGFloat((getReadConfigItem("size")))
        let font = UIFont.wn_font(name: fontName, size: isChapter ? fontSize+6.0 : fontSize)
        return font
    }
    
    func attributes(_ isChapter: Bool) -> [NSAttributedString.Key: Any] {
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineHeightMultiple = 1.0
        if isChapter {
            paragraphStyle.lineSpacing = 0
            paragraphStyle.paragraphSpacing = 0
            paragraphStyle.alignment = .left
        }else {
            paragraphStyle.lineSpacing = lineSpacing
            paragraphStyle.paragraphSpacing = paragraphSpacing
            paragraphStyle.alignment = .natural
        }
        return [.foregroundColor: textColor, .font: font(isChapter), .paragraphStyle: paragraphStyle]
    }
}

class SNKeyedArchiver: NSObject {
    /// 归档文件
    class func archiver(_ folderName: String?, _ fileName: String?, object: Any?) {
        if let foname = folderName, let finame = fileName {
            var path = CACHES_PATH + "/WalkNovel/\(foname)"
            if creat_file(path) {
                path += "/\(finame)"
                NSKeyedArchiver.archiveRootObject(object, toFile: path)
            }
        }
    }
    
    /// 解档文件
    class func unarchiver(_ folderName: String?, _ fileName: String?) -> Any? {
        if let foname = folderName, let finame = fileName {
            let path = CACHES_PATH + "/WalkNovel/\(foname)/\(finame)"
            do {
                return NSKeyedUnarchiver.unarchiveObject(withFile: path) as Any?
            }catch {
                return nil
            }
        }
        return nil
    }
    
    /// 是否存在
    class func isExist(_ folderName: String?, _ fileName: String? = nil) -> Bool {
        if let foname = folderName {
            var path = CACHES_PATH + "/WalkNovel/\(foname)"
            if let finame = fileName {
                path += "/\(finame)"
            }
            return FileManager.default.fileExists(atPath: path)
        }
        return false
    }
    
    /// 创建文件夹,如果存在则不创建
    class func creat_file(_ path: String) -> Bool {
        let fileManager = FileManager.default
        if fileManager.fileExists(atPath: path) { return true }
        do {
            try fileManager.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
            return true
        }catch {
            return false
        }
    }
}
